package smecta.client.print.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Timer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import smecta.client.print.util.DatabaseUtil;
import smecta.client.print.util.RowData;
import smecta.client.print.util.TableUtil;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.print.PrinterJob.JobStatus;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

@Component
public class LabelPrintController {

    @Autowired
    private DatabaseUtil databaseUtil;

    @FXML
    private TitledPane dataManagementPane;

    @FXML
    private Button addButton;

    @FXML
    private Button insertButton;

    @FXML
    private Button deleteButton;

    @FXML
    private Button saveButton;

    @FXML
    private Button refreshButton;

    @FXML
    private CheckBox selectAllCheckBox;

    @FXML
    private CheckBox largeLabelPrintCheckBox;

    @FXML
    private TitledPane dataPrintPane;

    @FXML
    private Button printPreviewButton;

    @FXML
    private Button printButton;

    @FXML
    private Button instantPrintButton;

    @FXML
    private TitledPane batchProcessPane;

    @FXML
    private ComboBox<String> columnNameComboBox;

    @FXML
    private TextField columnValueTextField;

    @FXML
    private Button batchProcessButton;

    @FXML
    private TitledPane labelSettingPane;

    @FXML
    private Button titleSettingButton;

    @FXML
    private Button printSettingButton;

//    @FXML
//    private Button formatSettingButton;

    @FXML
    private TitledPane otherFunctionPane;

    @FXML
    private Button printStatisticsButton;

    @FXML
    private Button exitSystemButton;


    @FXML
    private TableView<RowData> dataTableView;

    private Properties printSettings;
    private List<String> allPagesContent;
    private int currentPageIndex;


    public TableView<RowData> getDataTableView() {
        return dataTableView;
    }

    private ObservableList<RowData> tableData;

    @FXML
    public void initialize() {
        dataTableView.getItems().clear();
        TableUtil.generateTableColumns(dataTableView);
        columnNameComboBox.setItems(FXCollections.observableArrayList(TableUtil.getColumnsNames()));
        List<RowData> list = databaseUtil.queryItemConfigData(TableUtil.getColumnsIds());
        System.out.println("dataTableView:"+list.size());
        dataTableView.getItems().addAll(list);
        dataTableView.setEditable(true);


    }


    @FXML
    private void handleAdd() {
        System.out.println("handleAdd..");
        RowData newRow = new RowData();
        System.out.println( dataTableView.getColumns().get(0).getText()+":"+(dataTableView.getItems().size()+1));
        newRow.setCellValue( dataTableView.getColumns().get(0).getId(), new SimpleStringProperty(""+(dataTableView.getItems().size()+1)));
        dataTableView.getItems().add(newRow);

    }

    @FXML
    private void handleInsert() {
        int selectedIndex = dataTableView.getSelectionModel().getSelectedIndex();
        if (selectedIndex >= 0) {
            RowData newRow = new RowData();
            dataTableView.getItems().add(selectedIndex + 1, newRow);
            dataTableView.getSelectionModel().clearAndSelect(selectedIndex + 1);
        } else {
            RowData newRow = new RowData();
            dataTableView.getItems().add(newRow);
            dataTableView.getSelectionModel().clearAndSelect(dataTableView.getItems().size() - 1);
        }
    }

    @FXML
    private void handleDelete() {
        int selectedIndex = dataTableView.getSelectionModel().getSelectedIndex();
        if (selectedIndex >= 0) {
            dataTableView.getItems().remove(selectedIndex);
            if (selectedIndex < dataTableView.getItems().size()) {
                dataTableView.getSelectionModel().clearAndSelect(selectedIndex);
            } else {
                dataTableView.getSelectionModel().clearAndSelect(dataTableView.getItems().size() - 1);
            }
        } else {
        }
    }

    @FXML
    private void handleSave() {
        databaseUtil.saveAllDataByTable(dataTableView);

    }
    @FXML
    private void handleSelectAll() {
        boolean select=selectAllCheckBox.isSelected();
        for(RowData row:dataTableView.getItems())
        {
            row.setCheckBoxValue(new SimpleBooleanProperty(select));
        }
        dataTableView.refresh();
    }
    @FXML
    private void handleRefresh() {

        dataTableView.getItems().clear();
        List<RowData> list = databaseUtil.queryItemConfigData(TableUtil.getColumnsIds());
        System.out.println("dataTableView:"+list.size());
        dataTableView.getItems().addAll(list);
        dataTableView.setEditable(true);
    }

    @FXML
    private void handlePrintPreview() {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PrintPreviewView.fxml"));

            Stage stage = new Stage();
            Parent root= loader.load();
            PrintPreviewViewController controller = (PrintPreviewViewController)loader.getController();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.setTitle(printPreviewButton.getText());

            stage.show();
            controller.setDataTableView(dataTableView);
            controller.initialize_later();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    private void loadPrintSettings() {
        printSettings = new Properties();
        try (FileInputStream input = new FileInputStream("./samplePanel.ini")) {
            printSettings.load(input);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    private void generatePrintContent() {
        allPagesContent = new ArrayList<>();
        ObservableList<RowData> selectedItems = dataTableView.getSelectionModel().getSelectedItems();

        int labelWidth = Integer.parseInt(printSettings.getProperty("labelWidth", "200"));
        int labelHeight = Integer.parseInt(printSettings.getProperty("labelHeight", "100"));
        int labelColumns = Integer.parseInt(printSettings.getProperty("labelColumns", "1"));

        int columnWidth = labelWidth / labelColumns;
        int currentLabelCount = 0;

        for (RowData rowData : selectedItems) {
            int startSpindle = Integer.parseInt(rowData.getCellValue("Title6").get());
            int endSpindle = Integer.parseInt(rowData.getCellValue("Title7").get());

            int totalItem = endSpindle - startSpindle + 1;
            int totalLabels = totalItem / labelColumns;
            if (totalItem % labelColumns != 0) {
                totalLabels += 1;
            }

            for (int i = 0; i < totalLabels; i++) {
                StringBuilder htmlContent = new StringBuilder("<html><body>");
                htmlContent.append("<div style='border: 1px solid black; margin-bottom: 10px; padding: 10px; position: relative; width: ")
                        .append(labelWidth)
                        .append("px; height: ")
                        .append(labelHeight)
                        .append("px;'>");

                for (int l = 0; l < labelColumns; l++) {
                    int currentSpindle = startSpindle + i * labelColumns;
                    for (int j = 0; j < labelColumns && currentSpindle + j <= endSpindle; j++) {
                        int left = j * columnWidth;
                        htmlContent.append("<div style='position: absolute; left: ")
                                .append(left)
                                .append("px; top: 0; width: ")
                                .append(columnWidth)
                                .append("px; height: ")
                                .append(labelHeight)
                                .append("px;'>");

                        for (TableColumn<RowData, ?> column : dataTableView.getColumns()) {
                            String columnId = column.getId();
                            String columnValue = rowData.getCellValue(columnId) == null ? "" : rowData.getCellValue(columnId).get();

                            if (printSettings.getProperty(columnId + ".printable", "false").equals("true")) {
                                if (columnId.equals("Title6")) {
                                    htmlContent.append(createHtmlForTitle(columnId, String.valueOf(currentSpindle + j)));
                                } else {
                                    htmlContent.append(createHtmlForTitle(columnId, columnValue));
                                }
                            }
                        }
                        htmlContent.append("</div>");
                    }

                    currentLabelCount++;
                    if (currentLabelCount >= totalItem && currentLabelCount % labelColumns != 0) {
                        break;
                    }
                }
                htmlContent.append("</div></body></html>");
                allPagesContent.add(htmlContent.toString());
            }
        }
    }

    private String createHtmlForTitle(String columnId, String value) {
        String left = printSettings.getProperty(columnId + ".x", "0");
        String top = printSettings.getProperty(columnId + ".y", "0");
        String fontSize = printSettings.getProperty(columnId + ".fontSize", "12");

        return "<div style='position: absolute; left: " + left + "px; top: " + top + "px; font-size: " + fontSize + "px;'>" + value + "</div>";
    }

    private void printContent() {
        PrinterJob printerJob = PrinterJob.createPrinterJob();

        if (printerJob == null) {
            System.out.println("No printers are available.");
            return;
        }

        String defaultPrinterName = printSettings.getProperty("printerSelection", "");
        if (!defaultPrinterName.isEmpty()) {
            System.out.println("defaultPrinterName:" + defaultPrinterName);
            Printer defaultPrinter = Printer.getAllPrinters().stream()
                    .filter(printer -> printer.getName().equals(defaultPrinterName))
                    .findFirst()
                    .orElse(null);
            System.out.println("defaultPrinter:" + defaultPrinter);
            if (defaultPrinter != null) {
                printerJob.setPrinter(defaultPrinter);
            }
        }

        if (printerJob.showPrintDialog(printButton.getScene().getWindow())) {
            for (String pageContent : allPagesContent) {
                WebView webView = new WebView();
                WebEngine webEngine = webView.getEngine();
                webEngine.loadContent(pageContent);

                // Wait for the content to load
                webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
                    if (newState == Worker.State.SUCCEEDED) {
                        // Print the loaded content
                        if (printerJob.printPage(webView)) {
                            printerJob.endJob();
                        } else {
                            System.out.println("Failed to print the page.");
                        }
                    }
                });

                try {
                    // Give some time for the content to load and render
                    Thread.sleep(100); // You can adjust the sleep time if needed
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println("Print dialog was canceled.");
        }
    }

    @FXML
    private void handlePrint() {
        loadPrintSettings();
        generatePrintContent();
        printContent();
    }

    @FXML
    private void handleInstantPrint() {
        loadPrintSettings();
        generatePrintContent();
        printContentInstant();
    }
    private void printContentInstant() {
        String defaultPrinterName = printSettings.getProperty("printerSelection", "");
        Printer defaultPrinter = null;

        if (!defaultPrinterName.isEmpty()) {
            System.out.println("defaultPrinterName:" + defaultPrinterName);
            defaultPrinter = Printer.getAllPrinters().stream()
                    .filter(printer -> printer.getName().equals(defaultPrinterName))
                    .findFirst()
                    .orElse(null);
            System.out.println("defaultPrinter:" + defaultPrinter);
        }

        for (String pageContent : allPagesContent) {
            PrinterJob printerJob = PrinterJob.createPrinterJob();
            WebView webView=new WebView();
            if (printerJob == null) {
                System.out.println("No printers are available.");
                continue;
            }

            if (defaultPrinter != null) {
                printerJob.setPrinter(defaultPrinter);
            }

            WebEngine webEngine = webView.getEngine();
            webEngine.loadContent(pageContent);


            webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
                if (newState == Worker.State.SUCCEEDED) {
                    // Print the loaded content
                    if (printerJob.printPage(webView)) {
                        printerJob.endJob();
                        System.out.println("Printed page"+LocalDateTime.now());
                    } else {
                        System.out.println("Failed to print page"+LocalDateTime.now());
                    }
                }
            });
            try {
                // Give some time for the content to load and render
                Thread.sleep(1000); // You can adjust the sleep time if needed
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @FXML
    private void handleBatchProcess() {
        int index=columnNameComboBox.getSelectionModel().getSelectedIndex();

        String value=columnValueTextField.getText();
        System.out.println("index:"+index+" value:"+value);
        if(index<0)return;
        String id=TableUtil.getColumnsIds().get(index);
        System.out.println("id:"+id);
        for(RowData row:dataTableView.getItems())
        {
            row.setCellValue(id, new SimpleStringProperty(value));
        }
        dataTableView.refresh();
    }

    @FXML
    private void handleTitleSetting() {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/TitleSettingView.fxml"));

            Stage stage = new Stage();
            Parent root= loader.load();
            TitleSettingsController controller = (TitleSettingsController)loader.getController();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.setTitle(titleSettingButton.getText());

            stage.show();
            controller.setDataTableView(dataTableView);
            controller.readNameAndWithFromTable();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @FXML
    private void handlePrintSetting() {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PrintSettingsView.fxml"));

            Stage stage = new Stage();
            Parent root= loader.load();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.setTitle(printSettingButton.getText());
            stage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @FXML
    private void handleFormatSetting() {
    }

    @FXML
    private void handlePrintStatistics() {
    }

    @FXML
    private void handleExitSystem() {
    }
}
